<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="js/sparkmd5.min.js"></script>
  <script src="js/jquery.min.js"></script>
</head>
<body>
<input type="file" id="files">
<button type="button" onclick="test();">开始计算</button>
<script>
  let getMD5 = function (parent_folder, file, onSuccess, onFail, onProcess, callback) {
    let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
      //file = this.files[0],
      chunkSize = 2097152,                             // Read in chunks of 2MB
      chunks = Math.ceil(file.size / chunkSize),
      currentChunk = 0,
      spark = new SparkMD5.ArrayBuffer(),
      fileReader = new FileReader();

    fileReader.onload = function (e) {
      console.log('read chunk nr', currentChunk + 1, 'of', chunks);
      spark.append(e.target.result);                   // Append array buffer
      currentChunk++;

      if (currentChunk < chunks) {
        loadNext();
      } else {
        console.log('finished loading');
        //console.info('computed hash', spark.end());  // Compute hash
        callback(parent_folder, file, onSuccess, onFail, onProcess, spark.end());
      }
    };

    fileReader.onerror = function () {
      callback("error");
    };

    function loadNext() {
      let start = currentChunk * chunkSize,
        end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

      fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }

    loadNext();
  };
  function sendFile(upload_token, file, onSuccess, onFail, onProcess) {
    let loaded = 0;
    let total = file.size;  // total size of file
    let chunkSize = 2097152;                            // Read in chunks of 2MB
    let chunks = Math.ceil(file.size / chunkSize);
    let currentChunk = 0;
    let last_time = (new Date()).getTime();
    let hasError = false;

    function sendBlob(blob) {
      if(hasError) return;
      let xhr = new XMLHttpRequest();
      //let upload = xhr.upload;
      xhr.addEventListener('load',function(){
        if(xhr.status !== 200){
          hasError = true;
          onFail(5);
          return;
        }
        currentChunk++;
        loaded += chunkSize;                 //increasing loaded which is being used as start position for next chunk
        let time_cost = (new Date()).getTime()-last_time;
        last_time = (new Date()).getTime();
        let speed = (chunkSize*1000.0)/(time_cost); //上传速度，单位 Byte/s

        if(loaded <= total){            // if file is not completely uploaded
          onProcess(loaded, total, speed);
          blob = file.slice(loaded,loaded+chunkSize);  // getting next chunk
          sendBlob(blob);
        } else {                       // if file is uploaded completely
          loaded = total;            // just changed loaded which could be used to show status.
          onSuccess();
        }
      }, false);
      xhr.open("POST", "/upload?upload_token="+upload_token+"&chunk="+currentChunk+"&chunks="+chunks);
      xhr.overrideMimeType("application/octet-stream");
      xhr.send(blob);
    }

    sendBlob(file.slice(0,chunkSize));
  }
  function uploadAuth(parent_folder, file, onSuccess, onFail, onProcess, file_md5) {
    if(file_md5==="error") {
      onFail(2);//MD5计算失败
      return;
    }
    let api = "/upload/auth";
    fetch(api, {
      method: "POST",
      credentials: 'include',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        //params
        name: file.name,
        size: file.size,
        hash: file_md5,
        mime:file.type,
        parent_folder:parent_folder
      })
    }).then((response)=>{
      return response.json();
    }).then((response)=>{
      if(response.code===0) {
        //授权成功，需要上传
        sendFile(response.data.upload_token, file, onSuccess, onFail, onProcess);
        return;
      } else if(response.code===200) {
        //授权成功，不需要上传
        onSuccess();
        return;
      }
      //授权失败
      onFail(3);
    }).catch((error)=>{
      //授权失败
      console.log(error);
      onFail(4);
    });
  }
  function upload(parent_folder, file, onSuccess, onFail, onProcess) {
    if(file.size>1073741824) {
      //如果单文件体积大于1024MB，则报错
      onFail(1);
      return;
    }
    getMD5(parent_folder, file, onSuccess, onFail, onProcess, uploadAuth);

  }
  function test() {
    let file = document.getElementById('files').files[0];
    upload(1, file, ()=>{console.log("upload done")}, (c)=>{console.log("upload failed:"+c)}, (loaded, total, speed)=>{console.log("uploaded:"+loaded+"/"+total+"@"+speed+"B/s")});
  }
</script>
</body>
</html>